package certs

import (
	"context"
	"crypto/rsa"
	"crypto/x509"
	"fmt"
	"os"
	"reflect"
	"strings"
	"time"

	"github.com/pkg/errors"
	"github.com/wsva/lib_go/crypto"
	"go.uber.org/zap"
	agentutils "gopkg.openfuyao.cn/bkeagent/utils"
	"gopkg.openfuyao.cn/bkeagent/utils/pkiutil"
	bkenode "gopkg.openfuyao.cn/bkecommon/cluster/node"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/tools/clientcmd"
	certutil "k8s.io/client-go/util/cert"
	"sigs.k8s.io/cluster-api/util"
	"sigs.k8s.io/cluster-api/util/kubeconfig"
	"sigs.k8s.io/controller-runtime/pkg/client"

	bkev1beta1 "gopkg.openfuyao.cn/cluster-api-provider-bke/api/v1beta1"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/constant"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/log"
)

const (
	// TLSKeyDataName is the key used to store a TLS private key in the secret's data field.
	TLSKeyDataName = "tls.key"

	// TLSCrtDataName is the key used to store a TLS certificate in the secret's data field.
	TLSCrtDataName = "tls.crt"

	// ChainDataName is the key used to store a chain certificate in the secret's data field.
	ChainDataName = "trust-chain.crt"
)

type BKEKubernetesCertGenerator struct {
	certNamespace   string
	certClusterName string

	bkeCluster *bkev1beta1.BKECluster
	client     client.Client
	ctx        context.Context

	bkeCerts              pkiutil.Certificates
	caCertificatesContent map[string]map[string][]byte
	certificatesContent   map[string]map[string][]byte
	log                   *zap.SugaredLogger

	kubeConfigEndpoint   string
	needCreateKubeConfig bool
	isUserCustomCA       bool
}

func NewKubernetesCertGenerator(ctx context.Context, client client.Client, bkeCluster *bkev1beta1.BKECluster) *BKEKubernetesCertGenerator {
	return &BKEKubernetesCertGenerator{
		certNamespace:        bkeCluster.Namespace,
		certClusterName:      bkeCluster.Name,
		bkeCluster:           bkeCluster,
		client:               client,
		ctx:                  ctx,
		log:                  log.Named("certsGenerator").Named(utils.ClientObjNS(bkeCluster)),
		needCreateKubeConfig: true,
		kubeConfigEndpoint:   bkeCluster.Spec.ControlPlaneEndpoint.String(),
	}
}

func (k *BKEKubernetesCertGenerator) ConfigKubeConfig(endpoint string) {
	k.needCreateKubeConfig = true
	if endpoint == "" {
		k.kubeConfigEndpoint = k.bkeCluster.Spec.ControlPlaneEndpoint.String()
		return
	}
	k.kubeConfigEndpoint = endpoint
}

// LookUpOrGenerate generate kubernetes certs,exclude sa cert and kubeconfig
func (k *BKEKubernetesCertGenerator) LookUpOrGenerate() error {

	// 不管对于引导节点还是管理集群，直接加载对应的global-ca
	globalCASecret, err := k.LoadGlobalCA()
	if err != nil {
		k.log.Warnf("User don't upload global CA: %v", err)
	}

	// 如果找到了用户提供的全局 CA，则使用它；否则使用自签名 CA
	if globalCASecret != nil {
		k.fillInCertificateContent(globalCASecret[TLSCrtDataName], globalCASecret[TLSKeyDataName], GlobalCASecretName, true)
	}

	if err := k.prepareBkeCerts(false); err != nil {
		return err
	}
	if k.isUserCustomCA {
		// Load custom configuration from ConfigMap if available
		k.LoadConfigForCerts()
	}

	var needCreateSecret = false
	// 生成ca证书，以及其他证书
	for _, cert := range k.bkeCerts {

		exit, err := k.lookup(cert)
		if err != nil {
			return err
		}
		if exit {
			continue
		}

		k.log.Infof("generate cert %q, and save to secret %s/%s ", cert.Name, k.certNamespace, NewCertSecretName(k.certClusterName, cert.Name))
		needCreateSecret = true
		if cert.CAName != "" {
			if err := k.generateCertAndKeyWithCA(cert, cert.IsCA); err != nil {
				return err
			}
			continue
		}
		// 要确保生成CA证书是第一步，原本写死所以第一个循环一定在这执行
		if err := k.generateCACertAndKey(cert); err != nil {
			return err
		}
	}

	// 生成sa证书
	saCert := pkiutil.BKECertServiceAccount()
	exit, err := k.lookup(saCert)
	if err != nil {
		return err
	}
	if !exit {
		needCreateSecret = true
		if err := k.generateSAKeyAndPublicKey(pkiutil.BKECertServiceAccount()); err != nil {
			return err
		}
	}

	// 创建secret
	if needCreateSecret {
		return k.createCertificateSecrets()
	}
	return nil
}

func (k *BKEKubernetesCertGenerator) NeedGenerate() (bool, error) {
	bkeCerts := pkiutil.GetDefaultCertList()
	bkeCerts = append(bkeCerts, pkiutil.BKEAdminKubeConfig())

	for _, cert := range bkeCerts {
		exit, err := k.lookup(cert)
		if err != nil {
			return false, err
		}
		if !exit {
			log.Infof("need generate cert again: %v", cert.Name)
			return true, nil
		}
	}
	return false, nil
}

// prepareBkeCerts appends alternative names and IPs to the API server and etcd server certificates.
func (k *BKEKubernetesCertGenerator) prepareBkeCerts(isVerify bool) error {

	if k.isUserCustomCA {
		k.bkeCerts = pkiutil.GetUserCustomCerts()
		k.SetCertsCAName()
	} else {
		if isVerify {
			k.bkeCerts = pkiutil.GetCertsWithoutCA()
		} else {
			k.bkeCerts = pkiutil.GetDefaultCertList()
		}
	}
	// Append the BKE admin kubeconfig certificate if needed.
	if k.needCreateKubeConfig {
		k.bkeCerts = append(k.bkeCerts, pkiutil.BKEAdminKubeConfig())
	}

	// If there is no BKE cluster, return early.
	if k.bkeCluster == nil {
		return nil
	}

	bkeConfig := k.bkeCluster.Spec.ClusterConfig
	extraAltNames := k.getExtraAltNames()

	for _, cert := range k.bkeCerts {
		var altNames *certutil.AltNames
		var err error

		switch cert.BaseName {
		case pkiutil.APIServerCertAndKeyBaseName:
			altNames, err = pkiutil.GetAPIServerCertAltNamesFromBkeConfig(bkeConfig)
		case pkiutil.EtcdServerCertAndKeyBaseName:
			altNames, err = pkiutil.GetEtcdCertAltNamesFromBkeConfig(bkeConfig, true)
		case pkiutil.EtcdPeerCertAndKeyBaseName:
			altNames, err = pkiutil.GetEtcdCertAltNamesFromBkeConfig(bkeConfig, false)
		case pkiutil.ControllerManagerCertAndKeyBaseName, pkiutil.SchedulerCertAndKeyBaseName:
			altNames, err = pkiutil.GetMasterNodeAltNames(bkeConfig)
		default:
			continue
		}

		if err != nil {
			return errors.Wrapf(err, "failed to get alt names from bke config for %q", cert.BaseName)
		}

		if err := k.applyAltNamesToCert(cert, altNames, extraAltNames); err != nil {
			return err
		}
	}
	return nil
}

func (k *BKEKubernetesCertGenerator) getExtraAltNames() []string {
	var extraAltNames []string
	if k.bkeCluster.Spec.ControlPlaneEndpoint.IsValid() {
		extraAltNames = append(extraAltNames, k.bkeCluster.Spec.ControlPlaneEndpoint.Host)
	}

	// Add external load balancer IP if available
	if k.bkeCluster.Spec.ClusterConfig != nil {
		if loadBalanceIP := utils.GetExtraLoadBalanceIP(k.bkeCluster.Spec.ClusterConfig.CustomExtra); loadBalanceIP != "" {
			extraAltNames = append(extraAltNames, loadBalanceIP)
		}
	}
	return extraAltNames
}

// applyAltNamesToCert applies altNames to cert and appends extra SANs
func (k *BKEKubernetesCertGenerator) applyAltNamesToCert(cert *pkiutil.BKECert, altNames *certutil.AltNames, extraAltNames []string) error {
	cert.Config.AltNames.DNSNames = append(cert.Config.AltNames.DNSNames, altNames.DNSNames...)
	cert.Config.AltNames.IPs = append(cert.Config.AltNames.IPs, altNames.IPs...)
	if err := pkiutil.AppendSANsToAltNames(&cert.Config.AltNames, extraAltNames, cert.BaseName); err != nil {
		return errors.Wrapf(err, "failed to append alt names to %q", cert.BaseName)
	}
	return nil
}

// fillInCertificateContent fills in the certificate content
func (k *BKEKubernetesCertGenerator) fillInCertificateContent(crtBytes, keyBytes []byte, certName string, isCA bool) {
	data := map[string][]byte{
		TLSCrtDataName: crtBytes,
		TLSKeyDataName: keyBytes,
	}
	if isCA {
		if k.caCertificatesContent == nil {
			k.caCertificatesContent = make(map[string]map[string][]byte)
		}
		k.caCertificatesContent[certName] = data
		return
	}

	if k.certificatesContent == nil {
		k.certificatesContent = make(map[string]map[string][]byte)
	}
	k.certificatesContent[certName] = data
}

func (k *BKEKubernetesCertGenerator) lookup(cert *pkiutil.BKECert) (bool, error) {
	secretName := NewCertSecretName(k.certClusterName, cert.Name)
	// 对于kubeconfig，添加重试机制来处理HA字段的竞态条件
	maxRetries := 3
	retryDelay := 2 * time.Second

	for attempt := 1; attempt <= maxRetries; attempt++ {
		secret := &corev1.Secret{}
		err := k.client.Get(k.ctx, types.NamespacedName{Namespace: k.certNamespace, Name: secretName}, secret)
		if err != nil {
			if apierrors.IsNotFound(err) {
				return false, nil
			}
			return false, err
		}
		// 检查是否是 kubeconfig 证书
		if cert.Name == KubeConfigCertName {
			// 检查是否有 value 字段
			if secret.Data["value"] == nil {
				return false, nil
			}
			// 如果是 HA 集群，检查 ha 字段
			if IsHACluster(k.bkeCluster) {
				if secret.Data["ha"] == nil {
					if attempt < maxRetries-1 {
						time.Sleep(retryDelay)
						continue
					}
					return false, nil
				}
			}
		}

		return true, nil
	}

	// 如果所有重试都失败了
	k.log.Errorf("LOOKUP: failed to validate secret %s/%s for cert %s after %d attempts",
		k.certNamespace, secretName, cert.Name, maxRetries)
	return false, nil
}

func (k *BKEKubernetesCertGenerator) loadCaCertContent() error {
	bkeCaCerts := pkiutil.Certificates{
		pkiutil.BKECertRootCA(),
		pkiutil.BKECertEtcdCA(),
		pkiutil.BKECertFrontProxyCA(),
	}
	for _, cert := range bkeCaCerts {
		secretName := NewCertSecretName(k.certClusterName, cert.Name)
		secret := &corev1.Secret{}
		if err := k.client.Get(k.ctx, types.NamespacedName{Namespace: k.certNamespace, Name: secretName}, secret); err != nil {
			if apierrors.IsNotFound(err) {
				k.log.Debugf("secret %s/%s not found", k.certNamespace, secretName)
				continue
			}
			return err

		}
		k.fillInCertificateContent(secret.Data[TLSCrtDataName], secret.Data[TLSKeyDataName], cert.Name, true)
	}
	return nil
}

// createCertificateSecrets creates the certificate secrets
func (k *BKEKubernetesCertGenerator) createCertificateSecrets() error {
	k.log.Infof("CREATE_SECRETS: starting to create certificate secrets")
	k.log.Infof("CREATE_SECRETS: caCertificatesContent count: %d", len(k.caCertificatesContent))
	k.log.Infof("CREATE_SECRETS: certificatesContent count: %d", len(k.certificatesContent))

	// 将ca证书信息转移到certificatesContent中，方便后续统一创建
	for certName, data := range k.caCertificatesContent {
		k.log.Infof("CREATE_SECRETS: transferring CA cert %s to certificatesContent", certName)
		k.fillInCertificateContent(data[TLSCrtDataName], data[TLSKeyDataName], certName, false)
	}

	for certName, data := range k.certificatesContent {
		if certName == GlobalCASecretName {
			continue
		}
		secretName := NewCertSecretName(k.certClusterName, certName)
		k.log.Infof("CREATE_SECRETS: creating secret %s/%s for cert %s", k.certNamespace, secretName, certName)

		secret := &corev1.Secret{
			ObjectMeta: metav1.ObjectMeta{
				Name:      secretName,
				Namespace: k.certNamespace,
			},
			Data: data,
			Type: agentutils.BKESecretType,
		}
		controllerRef := metav1.NewControllerRef(k.bkeCluster, k.bkeCluster.GroupVersionKind())
		secret.SetOwnerReferences([]metav1.OwnerReference{*controllerRef})

		if err := k.client.Create(k.ctx, secret); err != nil {
			if apierrors.IsAlreadyExists(err) {
				if err := k.client.Delete(k.ctx, secret); err != nil {
					return errors.Errorf("failed to delete secret %q: %v", utils.ClientObjNS(secret), err)
				}
				if err := k.client.Create(k.ctx, secret); err != nil {
					return errors.Errorf("failed to create secret %q: %v", utils.ClientObjNS(secret), err)
				}
			}
		}
	}

	//最后创建kubeconfig
	if k.needCreateKubeConfig {
		if err := k.GenerateKubeConfig(k.kubeConfigEndpoint); err != nil {
			k.log.Errorf("CREATE_SECRETS: failed to create kubeconfig: %v", err)
			return errors.Errorf("failed to create kubeconfig secret: %v", err)
		}
	}

	return nil
}

// generateCACertAndKey generates a CA certificate and key.
func (k *BKEKubernetesCertGenerator) generateCACertAndKey(caCert *pkiutil.BKECert) error {
	if caCert.Name == pkiutil.BKEAdminKubeConfig().Name {
		return nil
	}
	crt, key, err := pkiutil.NewCertificateAuthority(caCert)
	if err != nil {
		return errors.Errorf("failed to generate CA cert and key: %v", err)
	}
	k.fillInCertificateContent(pkiutil.EncodeCertToPEM(crt), pkiutil.EncodeKeyToPEM(key), caCert.Name, true)
	return nil
}

// generateSAKeyAndPublicKey generates a service account key and public key.
func (k *BKEKubernetesCertGenerator) generateSAKeyAndPublicKey(saCert *pkiutil.BKECert) error {
	pub, key, err := pkiutil.NewRSACertAndKey(saCert)
	if err != nil {
		return errors.Errorf("failed to generate private key: %v", err)
	}
	pubBytes, err := pkiutil.EncodePublicKeyToPEM(pub)
	if err != nil {
		return errors.Errorf("failed to encode public key: %v", err)
	}
	k.fillInCertificateContent(pubBytes, pkiutil.EncodeKeyToPEM(key), saCert.Name, false)
	return nil
}

// generateCertAndKeyWithCA generates a certificate and key signed by the given CA.
func (k *BKEKubernetesCertGenerator) generateCertAndKeyWithCA(cert *pkiutil.BKECert, isCA bool) error {
	if k.caCertificatesContent == nil || len(k.caCertificatesContent) == 0 {
		if err := k.loadCaCertContent(); err != nil {
			return err
		}
	}
	caCertContent := make(map[string][]byte)
	for caName, data := range k.caCertificatesContent {
		if caName == cert.CAName {
			caCertContent = data
			break
		}

		tCaName := strings.TrimSuffix(cert.CAName, "-ca")
		if strings.Contains(tCaName, caName) {
			caCertContent = data
			break
		}
	}

	if len(caCertContent) == 0 {
		return errors.Errorf("failed to find CA certificate %q", cert.CAName)
	}

	caCrt, err := crypto.ParseCertsPEM(caCertContent[TLSCrtDataName])
	if err != nil {
		return errors.Errorf("failed to parse CA certificate %q: %v", cert.CAName, err)
	}
	if !caCrt[0].IsCA {
		return errors.Errorf("certificate %q is not a CA", cert.CAName)
	}

	caKey, err := crypto.ParsePrivateKeyPEM(caCertContent[TLSKeyDataName])
	if err != nil {
		return errors.Errorf("failed to parse CA private key %q: %v", cert.CAName, err)
	}

	rsaKey, ok := caKey.(*rsa.PrivateKey)
	if !ok {
		return errors.Errorf("CA private key %q is not RSA private key", cert.CAName)
	}

	crt, key, err := pkiutil.NewCertAndKey(cert, caCrt[0], rsaKey)
	if err != nil {
		return errors.Errorf("failed to generate cert and key: %v", err)
	}
	if HasServerAuth(crt) {
		log.Debugf("%q serving cert is signed for DNS names %v and IPs %v", cert.BaseName, crt.DNSNames, crt.IPAddresses)

	}

	k.fillInCertificateContent(pkiutil.EncodeCertToPEM(crt), pkiutil.EncodeKeyToPEM(key), cert.Name, isCA)
	return nil
}

// getCertificateFromSecret fetches and parses a certificate from a secret
func (k *BKEKubernetesCertGenerator) getCertificateFromSecret(certName string) (*x509.Certificate, error) {
	secretName := NewCertSecretName(k.certClusterName, certName)
	secret := &corev1.Secret{}

	secretKey := types.NamespacedName{
		Name:      secretName,
		Namespace: k.certNamespace,
	}
	if err := k.client.Get(k.ctx, secretKey, secret); err != nil {
		objNS := utils.ClientObjNS(secret)
		return nil, errors.Errorf("failed to get secret %q: %v", objNS, err)
	}

	crtBytes, ok := secret.Data[TLSCrtDataName]
	if !ok {
		objNS := utils.ClientObjNS(secret)
		return nil, errors.Errorf(
			"failed to find certificate data %q in secret %q",
			TLSCrtDataName,
			objNS,
		)
	}

	crt, err := crypto.ParseCertsPEM(crtBytes)
	if err != nil {
		objNS := utils.ClientObjNS(secret)
		return nil, errors.Errorf(
			"failed to parse certificate data %q in secret %q: %v",
			TLSCrtDataName,
			objNS,
			err,
		)
	}

	return crt[0], nil
}

// VerifyExpirationTime verifies the expiration time of the certificate
// If the certificate will expire in 30 days, an error will be returned
func (k *BKEKubernetesCertGenerator) VerifyExpirationTime() error {
	k.bkeCerts = pkiutil.Certificates{
		pkiutil.BKECertRootCA(),
		pkiutil.BKECertEtcdCA(),
		pkiutil.BKECertFrontProxyCA(),
	}
	for _, cert := range k.bkeCerts {
		crt, err := k.getCertificateFromSecret(cert.Name)
		if err != nil {
			return err
		}
		if crt.NotAfter.Before(time.Now().AddDate(0, 0, constant.CertExpireAlertDays)) {
			return errors.Errorf("certificate %q will expire in less than 30 days", cert.Name)
		}
	}
	return nil
}

// VerifyCertificateSans verifies the SANs of the certificate.
func (k *BKEKubernetesCertGenerator) VerifyCertificateSans() error {
	if err := k.prepareBkeCerts(true); err != nil {
		return err
	}

	for _, cert := range k.bkeCerts {
		if cert.Name == KubeConfigCertName {
			continue
		}
		crt, err := k.getCertificateFromSecret(cert.Name)
		if err != nil {
			return err
		}

		if !reflect.DeepEqual(cert.Config.AltNames.DNSNames, crt.DNSNames) {
			return errors.Errorf("failed to verify certificate %q: SANs are not equal", cert.Name)
		}

		var certAltIps, crtAltIps []string
		for _, ip := range cert.Config.AltNames.IPs {
			certAltIps = append(certAltIps, ip.String())
		}
		for _, ip := range crt.IPAddresses {
			crtAltIps = append(crtAltIps, ip.String())
		}

		if !reflect.DeepEqual(certAltIps, crtAltIps) {
			return errors.Errorf("failed to verify certificate %q: SANs are not equal", cert.Name)
		}
	}
	return nil
}

// GenerateKubeConfig generates the kubeconfig for the cluster, and stores it in the secret.
func (k *BKEKubernetesCertGenerator) GenerateKubeConfig(endpoint string) error {
	k.log.Infof("GENERATE_KUBECONFIG: starting to generate kubeconfig for cluster %s", k.certClusterName)
	k.log.Infof("GENERATE_KUBECONFIG: endpoint = %s", endpoint)
	k.log.Infof("GENERATE_KUBECONFIG: IsHACluster = %v", IsHACluster(k.bkeCluster))

	err := kubeconfig.CreateSecretWithOwner(k.ctx, k.client, util.ObjectKey(k.bkeCluster), endpoint, metav1.OwnerReference{
		APIVersion: bkev1beta1.GroupVersion.String(),
		Kind:       "BKECluster",
		Name:       k.bkeCluster.Name,
		UID:        k.bkeCluster.UID,
	})
	if err != nil && !apierrors.IsAlreadyExists(err) {
		k.log.Errorf("GENERATE_KUBECONFIG: failed to create kubeconfig secret: %v", err)
		return errors.Errorf("failed to create kubeconfig secret: %v", err)
	}
	k.log.Infof("GENERATE_KUBECONFIG: kubeconfig secret created successfully")

	//是ha集群在设置一个以域名为主机名的kubeconfig，非域名的供程序使用，域名的给节点使用，同时需要环境初始化配置域名解析
	if IsHACluster(k.bkeCluster) {
		k.log.Infof("GENERATE_KUBECONFIG: processing HA cluster kubeconfig")
		// 登一秒 太快了get不到
		k.log.Infof("GENERATE_KUBECONFIG: waiting 1 second before processing HA kubeconfig")
		time.Sleep(1 * time.Second)

		secretName := NewCertSecretName(k.certClusterName, "kubeconfig")
		k.log.Infof("GENERATE_KUBECONFIG: getting kubeconfig secret %s/%s", k.certNamespace, secretName)
		secret := &corev1.Secret{}
		if err := k.client.Get(k.ctx, types.NamespacedName{Name: secretName, Namespace: k.certNamespace}, secret); err != nil {
			k.log.Errorf("GENERATE_KUBECONFIG: failed to get kubeconfig secret %s/%s: %v", k.certNamespace, secretName, err)
			return errors.Errorf("failed to get secret %q: %v", utils.ClientObjNS(secret), err)
		}
		k.log.Infof("GENERATE_KUBECONFIG: successfully retrieved kubeconfig secret %s/%s", k.certNamespace, secretName)

		kubeconfigBytes, ok := secret.Data["value"]
		if !ok {
			k.log.Errorf("GENERATE_KUBECONFIG: kubeconfig secret %s/%s missing 'value' field", k.certNamespace, secretName)
			return errors.Errorf("failed to find kubeconfig data %q in secret %q", "value", utils.ClientObjNS(secret))
		}
		k.log.Infof("GENERATE_KUBECONFIG: found 'value' field in kubeconfig secret %s/%s", k.certNamespace, secretName)

		kubeconfig, err := clientcmd.Load(kubeconfigBytes)
		if err != nil {
			k.log.Errorf("GENERATE_KUBECONFIG: failed to load kubeconfig from secret %s/%s: %v", k.certNamespace, secretName, err)
			return errors.Errorf("failed to load kubeconfig: %v", err)
		}
		k.log.Infof("GENERATE_KUBECONFIG: successfully loaded kubeconfig from secret %s/%s", k.certNamespace, secretName)

		newEndpoint := fmt.Sprintf("https://%s:%d", constant.MasterHADomain, k.bkeCluster.Spec.ControlPlaneEndpoint.Port)
		k.log.Infof("GENERATE_KUBECONFIG: updating kubeconfig endpoint to %s", newEndpoint)
		kubeconfig.Clusters[k.certClusterName].Server = newEndpoint

		kubeconfigBytes, err = clientcmd.Write(*kubeconfig)
		if err != nil {
			k.log.Errorf("GENERATE_KUBECONFIG: failed to write kubeconfig: %v", err)
			return errors.Errorf("failed to write kubeconfig: %v", err)
		}
		k.log.Infof("GENERATE_KUBECONFIG: successfully wrote kubeconfig")

		secret.Data["ha"] = kubeconfigBytes
		k.log.Infof("GENERATE_KUBECONFIG: adding 'ha' field to kubeconfig secret %s/%s", k.certNamespace, secretName)
		if err := k.client.Update(k.ctx, secret); err != nil {
			k.log.Errorf("GENERATE_KUBECONFIG: failed to update kubeconfig secret %s/%s: %v", k.certNamespace, secretName, err)
			return errors.Errorf("failed to update secret %q: %v", utils.ClientObjNS(secret), err)
		}
		k.log.Infof("GENERATE_KUBECONFIG: successfully updated kubeconfig secret %s/%s with 'ha' field", k.certNamespace, secretName)
	} else {
		k.log.Infof("GENERATE_KUBECONFIG: not a HA cluster, skipping HA processing")
	}

	k.log.Infof("GENERATE_KUBECONFIG: kubeconfig generation completed successfully")
	return nil
}

func NewCertSecretName(clusterName, certName string) string {
	return fmt.Sprintf("%s-%s", clusterName, certName)
}

func HasServerAuth(cert *x509.Certificate) bool {
	for i := range cert.ExtKeyUsage {
		if cert.ExtKeyUsage[i] == x509.ExtKeyUsageServerAuth {
			return true
		}
	}
	return false
}

func IsHACluster(bkeCluster *bkev1beta1.BKECluster) bool {
	if bkeCluster.Spec.ControlPlaneEndpoint.IsValid() {
		host := bkeCluster.Spec.ControlPlaneEndpoint.Host
		nodes := bkenode.Nodes(bkeCluster.Spec.ClusterConfig.Nodes)
		if nodes.Filter(bkenode.FilterOptions{"IP": host}).Length() == 0 {
			return true
		}
	}
	return false
}

// LoadGlobalCA load global CA certs and key from secret
func (k *BKEKubernetesCertGenerator) LoadGlobalCA() (map[string][]byte, error) {
	if data, found, err := k.tryLoadGlobalCAFromSecret(); err != nil || found {
		return data, err
	}
	localData, err := k.loadLocalGlobalCA()
	if err != nil || localData == nil {
		return nil, err
	}
	if err := k.createGlobalCASecret(localData); err != nil && !apierrors.IsAlreadyExists(err) {
		return nil, err
	}
	k.isUserCustomCA = true
	return localData, nil
}

func (k *BKEKubernetesCertGenerator) tryLoadGlobalCAFromSecret() (map[string][]byte, bool, error) {
	secret := &corev1.Secret{}
	err := k.client.Get(k.ctx, types.NamespacedName{Namespace: GlobalCANamespace, Name: GlobalCASecretName}, secret)
	if err != nil {
		if apierrors.IsNotFound(err) {
			k.log.Infof("global CA secret %s/%s not found", GlobalCANamespace, GlobalCASecretName)
			return nil, false, nil
		}
		return nil, false, errors.Errorf("failed to get global CA secret %s/%s:%v", GlobalCANamespace, GlobalCASecretName, err)
	}
	if err := k.validateGlobalCASecret(secret); err != nil {
		k.log.Warnf("invalid global CA secret %s/%s: %v", GlobalCANamespace, GlobalCASecretName, err)
		return nil, false, nil
	}
	k.log.Infof("found valid global CA in secret %s/%s", GlobalCANamespace, GlobalCASecretName)
	k.isUserCustomCA = true
	return secret.Data, true, nil
}

func (k *BKEKubernetesCertGenerator) validateGlobalCASecret(secret *corev1.Secret) error {
	if secret.Data == nil {
		return errors.Errorf("secret has no data")
	}
	crtBytes, hasCert := secret.Data[TLSCrtDataName]
	keyBytes, hasKey := secret.Data[TLSKeyDataName]
	if !hasCert || !hasKey || len(crtBytes) == 0 || len(keyBytes) == 0 {
		return errors.Errorf("secret missing certificate or key")
	}
	if _, err := pkiutil.ParseCertsPEM(crtBytes); err != nil {
		return errors.Errorf("invalid certificate: %v", err)
	}
	if _, err := pkiutil.ParsePrivateKeyPEM(keyBytes); err != nil {
		return errors.Errorf("invalid private key: %v", err)
	}
	return nil
}

func (k *BKEKubernetesCertGenerator) loadLocalGlobalCA() (map[string][]byte, error) {
	crtBytes, err := os.ReadFile(GlobalCACertPath)
	if err != nil {
		k.log.Warnf("global CA cert file read error: path=%s, error=%v", GlobalCACertPath, err)
		return nil, nil
	}
	if len(crtBytes) == 0 {
		k.log.Warnf("global CA cert file is empty: path=%s", GlobalCACertPath)
		return nil, nil
	}
	keyBytes, err := os.ReadFile(GlobalCAKeyPath)
	if err != nil {
		k.log.Warnf("global CA key file read error: path=%s, error=%v", GlobalCAKeyPath, err)
		return nil, nil
	}
	if len(keyBytes) == 0 {
		k.log.Warnf("global CA key file is empty: path=%s", GlobalCAKeyPath)
		return nil, nil
	}
	if _, err := pkiutil.ParseCertsPEM(crtBytes); err != nil {
		k.log.Errorf("invalid local CA certificate: path=%s, error=%v", GlobalCACertPath, err)
		return nil, errors.Errorf("invalid local CA certificate: %v", err)
	}
	if _, err := pkiutil.ParsePrivateKeyPEM(keyBytes); err != nil {
		k.log.Errorf("invalid local CA key: path=%s, error=%v", GlobalCAKeyPath, err)
		return nil, errors.Errorf("invalid local CA key: %v", err)
	}
	chainBytes, err := os.ReadFile(CertChainPath)
	if err != nil {
		k.log.Warnf("global CA cert file read error: path=%s, error=%v", CertChainPath, err)
	}
	if len(chainBytes) == 0 {
		k.log.Warnf("global CA cert file is empty: path=%s", CertChainPath)
	}
	if _, err := pkiutil.ParseCertsPEM(chainBytes); err != nil {
		k.log.Errorf("invalid local chain certification: path=%s, error=%v", CertChainPath, err)
	}
	return map[string][]byte{TLSCrtDataName: crtBytes, TLSKeyDataName: keyBytes, ChainDataName: chainBytes}, nil
}

func (k *BKEKubernetesCertGenerator) createGlobalCASecret(data map[string][]byte) error {
	secret := &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{Namespace: GlobalCANamespace, Name: GlobalCASecretName},
		Data:       data,
		Type:       agentutils.BKESecretType,
	}
	if k.bkeCluster != nil {
		controllerRef := metav1.NewControllerRef(k.bkeCluster, k.bkeCluster.GroupVersionKind())
		secret.SetOwnerReferences([]metav1.OwnerReference{*controllerRef})
	}
	if err := k.client.Create(k.ctx, secret); err != nil {
		if apierrors.IsAlreadyExists(err) {
			k.log.Infof("global CA secret %s/%s already exists", GlobalCANamespace, GlobalCASecretName)
			return err
		}
		return errors.Errorf("failed to create global CA secret %s/%s: %v", GlobalCANamespace, GlobalCASecretName, err)
	}
	k.log.Infof("created global CA secret %s/%s from local files", GlobalCANamespace, GlobalCASecretName)
	return nil
}

// SetCertsCAName set the CAName for the certs which are not self-signing
func (k *BKEKubernetesCertGenerator) SetCertsCAName() {
	for i, cert := range k.bkeCerts {
		if cert.BaseName == pkiutil.CACertAndKeyBaseName ||
			cert.BaseName == pkiutil.FrontProxyCACertAndKeyBaseName ||
			cert.BaseName == pkiutil.EtcdCACertAndKeyBaseName {
			if k.isUserCustomCA {
				k.bkeCerts[i].CAName = "global-ca"
				k.bkeCerts[i].IsCA = true
			}
		}
	}
}

// LoadConfigForCerts load user custom certification csr json and signing policy json
func (k *BKEKubernetesCertGenerator) LoadConfigForCerts() {
	loader := NewCertConfigLoader(k.ctx, k.client, k.bkeCluster, k.log)

	cfg, err := loader.LoadConfigMapData()
	if err != nil {
		k.log.Warnf("Failed to load certificate configuration from ConfigMap: %v", err)
	}

	if !k.hasAnyConfig(cfg) {
		cfg = k.loadFromLocalAndPersist(loader)
	}
	if !k.canApplyConfig(cfg) {
		return
	}
	k.applyConfig(loader, cfg)
}

// hasAnyConfig check whether to have config files
func (k *BKEKubernetesCertGenerator) hasAnyConfig(cfg *CertConfigData) bool {
	if cfg == nil {
		return false
	}
	for _, ok := range cfg.AvailableKeys {
		if ok {
			return true
		}
	}
	return false
}

// loadFromLocalAndPersist load from local files if ConfigMap not exist
func (k *BKEKubernetesCertGenerator) loadFromLocalAndPersist(loader *CertConfigLoader) *CertConfigData {

	localData, err := loader.LoadLocalConfigData()
	if err != nil {
		k.log.Warnf("Failed to load local certificate configuration: %v", err)
		return nil
	}
	if localData == nil {
		k.log.Infof("Local certificate configuration not found. Using default cert logic.")
		return nil
	}
	k.log.Infof("Loaded certificate configuration from local files.")
	if err := loader.SaveConfigMapData(localData); err != nil {
		k.log.Warnf("Failed to save local certificate configuration into ConfigMap: %v", err)
	} else {
		k.log.Infof("Saved local certificate configuration into ConfigMap %s/%s", CertConfigMapNamespace, CertConfigMapName)
	}
	return localData
}

// canApplyConfig determine if can get config successfully to apply to bkecert
func (k *BKEKubernetesCertGenerator) canApplyConfig(cfg *CertConfigData) bool {
	if k.bkeCerts == nil {
		return false
	}
	return cfg != nil
}

// applyConfig apply user custom config to bkecerts
func (k *BKEKubernetesCertGenerator) applyConfig(loader *CertConfigLoader, cfg *CertConfigData) {
	if err := loader.ApplyConfigToCerts(k.bkeCerts, cfg, k.certClusterName); err != nil {
		k.log.Warnf("Failed to apply certificate configuration: %v", err)
		return
	}
	k.log.Infof("Successfully loaded and applied certificate configuration")
}
